package tools.data;

import constants.ServerConstants;
import tools.HexTool;

import java.awt.*;
import java.io.*;
import java.nio.charset.Charset;

public class MaplePacketLittleEndianWriter {
    private ByteArrayOutputStream baos;
    private static Charset ASCII;

    public MaplePacketLittleEndianWriter() {
        this(32);
    }

    public MaplePacketLittleEndianWriter(int size) {
        this.baos = new ByteArrayOutputStream(size);
    }

    private void baosWrite(byte b) {
        this.baos.write((int) b);
    }

    public byte[] getPacket() {
        return this.baos.toByteArray();
    }

    @Override
    public String toString() {
        return HexTool.toString(this.baos.toByteArray());
    }

    public void writeZeroBytes(int i) {
        for (int x = 0; x < i; ++x) {
            this.baosWrite((byte) 0);
        }
    }

    public void write(byte[] b) {
        for (int x = 0; x < b.length; ++x) {
            this.baosWrite(b[x]);
        }
    }

    public void write(byte b) {
        this.baosWrite(b);
    }

    public void write(int b) {
        this.baosWrite((byte) b);
    }

    public void write(boolean b) {
        this.baosWrite((byte) (byte) (b ? 1 : 0));
    }

    public void writeShort(int i) {
        this.baosWrite((byte) (i & 0xFF));
        this.baosWrite((byte) (i >>> 8 & 0xFF));
    }

    public void writeInt(int i) {
        this.baosWrite((byte) (i & 0xFF));
        this.baosWrite((byte) (i >>> 8 & 0xFF));
        this.baosWrite((byte) (i >>> 16 & 0xFF));
        this.baosWrite((byte) (i >>> 24 & 0xFF));
    }

    public void writeReversedInt(long l) {
        this.baosWrite((byte) (int) (l >>> 32 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 40 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 48 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 56 & 0xFFL));
    }

    public void writeAsciiString(String s) {
        this.write(s.getBytes(MaplePacketLittleEndianWriter.ASCII));
    }

    public void writeAsciiString(String s, int max) {
        if (s.getBytes(MaplePacketLittleEndianWriter.ASCII).length > max) {
            s = s.substring(0, max);
        }
        this.write(s.getBytes(MaplePacketLittleEndianWriter.ASCII));
        for (int i = s.getBytes(MaplePacketLittleEndianWriter.ASCII).length; i < max; ++i) {
            this.baosWrite((byte) 0);
        }
    }

    public void writeMapleAsciiString(String s) {
        this.writeShort((int) (short) s.getBytes(MaplePacketLittleEndianWriter.ASCII).length);
        this.writeAsciiString(s);
    }

    public void writeMapleAsciiString(String s, int max) {
        if (s.getBytes(MaplePacketLittleEndianWriter.ASCII).length > max) {
            s = s.substring(0, max);
        }
        this.writeShort((int) (short) s.getBytes(MaplePacketLittleEndianWriter.ASCII).length);
        this.write(s.getBytes(MaplePacketLittleEndianWriter.ASCII));
        for (int i = s.getBytes(MaplePacketLittleEndianWriter.ASCII).length; i < max; ++i) {
            this.baosWrite((byte) 0);
        }
    }

    public void writeNullTerminatedCharString(String s) {
        byte[] bytes;
        byte[] strBytes = bytes = s.getBytes(MaplePacketLittleEndianWriter.ASCII);
        for (byte b : bytes) {
            this.baosWrite(b);
            this.baosWrite((byte) 0);
        }
    }

    public void writeBoolean(boolean b) {
        this.baosWrite((byte) (byte) (b ? 1 : 0));
    }

    public void writePos(Point s) {
        this.writeShort(s.x);
        this.writeShort(s.y);
    }

    public void writeRect(Rectangle s) {
        this.writeInt(s.x);
        this.writeInt(s.y);
        this.writeInt(s.x + s.width);
        this.writeInt(s.y + s.height);
    }

    public void writeLong(long l) {
        this.baosWrite((byte) (int) (l & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 8 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 16 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 24 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 32 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 40 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 48 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 56 & 0xFFL));
    }

    public void writeReversedLong(long l) {
        this.baosWrite((byte) (int) (l >>> 32 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 40 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 48 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 56 & 0xFFL));
        this.baosWrite((byte) (int) (l & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 8 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 16 & 0xFFL));
        this.baosWrite((byte) (int) (l >>> 24 & 0xFFL));
    }

    public void writeFile(File file) {
        try {
            InputStream is = new FileInputStream(file);
            long length = file.length();
            if (length > 2147483647L) {
                System.err.println("档案太大");
                return;
            }
            byte[] bytes = new byte[(int) length];
            int offset = 0;
            for (int numRead = 0; offset < bytes.length && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0; offset += numRead) {
            }
            is.close();
            if (offset < bytes.length) {
                System.err.println("无法完整读取档案:" + file.getName());
                return;
            }
            this.writeInt(bytes.length);
            this.write(bytes);
        } catch (IOException e) {
            System.err.println("读取档案失败:" + e);
        }
    }

    static {
        ASCII = Charset.forName(ServerConstants.MAPLE_TYPE.getANSI());
    }
}
